在 Linux 系統中, 「一切皆檔案」 抽象模型將所有輸入/輸出來源——從一般檔案到網路 通訊端——映射為統一的字節流。這種整合介面讓系統層級的輸入/輸出能一致地管理伺服器與客戶端流程,並在多核心處理器上進行交易。 系統層級輸入/輸出 以管理 伺服器流程 與 客戶端流程 跨 多核心處理器。
統一模型
無論程式存取的是 一般檔案、 目錄或硬體設備如 網路介面卡,都使用相同的基礎操作。如圖 11.2 所示的「硬體組織結構」,作業系統透過 I/O 匯流排連結中央處理器與記憶體至外部裝置,將網路視為檔案,以簡化多核心處理器上的併發控制。 硬體組織結構(圖 11.2),作業系統透過 I/O 匯流排將中央處理器與記憶體連接至裝置,把網路當作檔案處理,以簡化 多核心處理器上的併發控制。
強健的輸入/輸出與資料標籤
為處理 短量讀寫 (當請求讀取的位元組數 $k$ 大於等於可用位元組數 $m$ 時), Rio(強健輸入/輸出)套件 提供 rio_readinitb 用於 緩衝輸入。資料標籤由 stat管理;權限如 O_RDWR 與 S_IROTH 則受 umask。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
What is the output of a program that opens 'foo.txt' (getting fd 3), closes it, then opens 'baz.txt'?
$fd2 = 3$
$fd2 = 4$
$fd2 = 0$
Segmentation Fault
✅ Correct!
Linux always assigns the lowest-available file descriptor. Since 3 was freed by Close(), it is reused.❌ Incorrect
Recall the 'Lowest-Available Descriptor Rule'. Once fd 3 is closed, it is the first available slot after 0, 1, and 2.QUESTION 2
If a disk file 'foobar.txt' contains 'foobar' and a process forks after opening it, what is the output if both parent and child read 1 byte?
Both read 'f'
One reads 'f', the other reads 'o'
Both read 'fo'
The child gets an error
✅ Correct!
Because the child inherits the parent's descriptor table, they share the same entry in the Open File Table and thus share the 'Current file position'.❌ Incorrect
A fork() duplicates the descriptor table, but both copies point to the same open file entry in the kernel.QUESTION 3
Which constant represents opening a file for both reading and writing?
O_RDONLY
O_WRONLY
O_RDWR
S_IROTH
✅ Correct!
O_RDWR stands for Open Read/Write.❌ Incorrect
O_RDONLY is read-only; O_WRONLY is write-only. O_RDWR combines both.QUESTION 4
What is a 'Short Count' in the context of Unix I/O?
A file with zero bytes.
When read() or write() transfers fewer bytes than requested.
A limited number of file descriptors.
A CPU clock cycle error.
✅ Correct!
This is common in network sockets where $k \ge m$. The Rio package is used to handle this robustly.❌ Incorrect
Short counts occur when the kernel returns fewer bytes than requested due to EOF or network buffering.QUESTION 5
How does the OS manage the network adapter in the 'Everything is a File' model?
It bypasses the I/O bus entirely.
It maps the adapter to a socket descriptor.
It treats it as a CPU register.
It uses a special network-only language.
✅ Correct!
By treating the network adapter as a file (socket), the system allows standard read/write logic to handle network communication.❌ Incorrect
The hardware organization treats the adapter as an I/O device accessible via file descriptors.Module Case Study: The Robust I/O Redirector
Implementing Redirection and Buffered Reads
A developer is tasked with redirecting the standard input of a process to a log file 'input.log' and then reading the file using the Rio (Robust I/O) package to ensure no data is lost due to short counts on a high-concurrency multi-core system.
Q
1. Which system call would you use to redirect standard input (descriptor 0) to a new file descriptor 'fd'?
Solution:
You would use
You would use
dup2(fd, STDIN_FILENO);. This call atomically closes descriptor 0 (if open) and copies the entry of 'fd' into descriptor 0, effectively redirecting the input stream.Q
2. Why is 'Rio buffered reading' preferred over standard read() when dealing with network sockets?
Solution:
Rio buffered reading (using
Rio buffered reading (using
rio_readinitb and rio_readlineb) reduces system call overhead by copying text lines from an internal buffer. Most importantly, it robustly handles 'short counts' common in network transactions where read() might return before receiving all requested bytes.Q
3. If the process has a umask of 022 and creates a file with S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666), what are the final permissions?
Solution:
The final permissions will be 0644 (
The final permissions will be 0644 (
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH). The umask 022 masks out the write permissions for 'group' and 'others', ensuring the file is not globally writable despite the open() flags.